package algorithms;

import Entities.Calendar;

public class RandomWalkHC extends HillClimbing {
	private static TYPE_OF_RANDOM_WALK typeOfRandomWalk;
	private	static double randomWalkFactor = 0.0; // this factor will help to determine how many random moves we will walk
	private static int fixedNumberOfRandomWalk = 0;
	private int numberOfHeuristicCallsToBest = 0;
	
	/**
	 * Set RandomWalkFactor value
	 * @param randomWalkFactor should be between 0 to 1
	 */
	public static void setRandomWalkFactor(double randomWalkFactor) {
		if ((randomWalkFactor <= 0.0) || (randomWalkFactor >= 1.0)){
			throw new IllegalArgumentException("randomWalkFactor should be between 0 to 1 not inclusive");
		}
		RandomWalkHC.randomWalkFactor = randomWalkFactor;
	}
	
	public Calendar searchLocal(){
		Calendar next = null, best = null;
		int numberOfMoves;
		next = super.searchLocal();
		best = next; // initialize best
		numberOfHeuristicCallsToBest = numberOfHeuristicCalls; // from Hill Climbing
		while (maxOfHeuristicCalls > numberOfHeuristicCalls){ // assuming upperBound initialized > 0 	
			numberOfMoves = getNumberOfMoves();
			if (numberOfMoves == 0){
				break; // in case we have too little Nodes to expand 
			}
			next = randomWalk(next, numberOfMoves);
			next = super.searchLocal(next);				
			if (next.isBetter(best)){
				numberOfHeuristicCallsToBest = numberOfHeuristicCalls;
				best = next; // save best calendar so far
			}
		}
		return best;

	}

	private int getNumberOfMoves() {
		int res = 0;
		if (TYPE_OF_RANDOM_WALK.FIXED == typeOfRandomWalk){
			res = fixedNumberOfRandomWalk;
		}
		else if (TYPE_OF_RANDOM_WALK.FACTOR == typeOfRandomWalk){
			res = (int) ((maxOfHeuristicCalls - numberOfHeuristicCalls)*randomWalkFactor);			
		}
		return res;
	}

	/**
	 * This function walks randomly from the given calendar, 
	 * therefore we do not increment the number of heuristic calls 
	 */
	private Calendar randomWalk(Calendar startCalendar, int numberOfMoves) {
		Calendar curr = startCalendar;
		for(int i = 0 ; i < numberOfMoves ; i++){
			curr = curr.getRandomNeighbour();
		}
		return curr;
	}

	public void reset() {
		numberOfHeuristicCalls = 0;
		numberOfHeuristicCallsToBest = 0;
	}
	
	public static double getRandomWalkFactor() {
		return randomWalkFactor;
	}
	public static int getFixedNumberOfRandomWalk() {
		return fixedNumberOfRandomWalk;
	}
	public static TYPE_OF_RANDOM_WALK getTypeOfRandomWalk() {
		return typeOfRandomWalk;
	}
	public static void setTypeOfRandomWalk(TYPE_OF_RANDOM_WALK toSet) {
		typeOfRandomWalk = toSet;
	}	
	public static void setFixedNumberOfRandomWalk(int toSet) {
		fixedNumberOfRandomWalk = toSet;
	}

	public String toString(){
		return "SAHC Random Walk";
	}

	public int getNumberOfHeuristicCallsToBest() {
		return numberOfHeuristicCallsToBest;
	}
}